{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Namespace(base_dir='../data/MegaDepth_undistort', exclude_tag='excl_test', im_target_ratio=1.5, max_scene_pairs=500, min_overlap_ratio=0.35, save_dir='../data_pairs/generated')\n",
      "Start process 182 scenes ......\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0000 ims:673 total valid pairs:63928 selected pairs:500\n",
      "Scene:0001 ims:257 total valid pairs:4341 selected pairs:500\n",
      "Scene:0002 ims:579 total valid pairs:22516 selected pairs:500\n",
      "Scene:0003 ims:409 total valid pairs:33786 selected pairs:500\n",
      "Scene:0004 ims:523 total valid pairs:101061 selected pairs:500\n",
      "Scene:0005 ims:204 total valid pairs:1132 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0007 ims:515 total valid pairs:18447 selected pairs:500\n",
      "Scene:0012 ims:277 total valid pairs:17296 selected pairs:500\n",
      "Scene:0013 ims:314 total valid pairs:23885 selected pairs:500\n",
      "Scene:0015 ims:290 total valid pairs:2294 selected pairs:500\n",
      "Scene:0016 ims:59 total valid pairs:314 selected pairs:259\n",
      "Scene:0017 ims:356 total valid pairs:8075 selected pairs:500\n",
      "Skip scene 0019\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0020 ims:107 total valid pairs:1983 selected pairs:500\n",
      "Skip scene 0021\n",
      "Scene:0022 ims:356 total valid pairs:9403 selected pairs:500\n",
      "Scene:0023 ims:293 total valid pairs:23754 selected pairs:500\n",
      "Skip scene 0024\n",
      "Skip scene 0025\n",
      "Scene:0026 ims:78 total valid pairs:3091 selected pairs:248\n",
      "Scene:0027 ims:270 total valid pairs:3762 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0033 ims:108 total valid pairs:2146 selected pairs:500\n",
      "Scene:0034 ims:133 total valid pairs:1659 selected pairs:500\n",
      "Scene:0036 ims:447 total valid pairs:23419 selected pairs:500\n",
      "Scene:0037 ims:114 total valid pairs:8059 selected pairs:500\n",
      "Scene:0039 ims:222 total valid pairs:6554 selected pairs:500\n",
      "Scene:0041 ims:150 total valid pairs:1112 selected pairs:500\n",
      "Scene:0042 ims:291 total valid pairs:10034 selected pairs:500\n",
      "Scene:0043 ims:91 total valid pairs:3498 selected pairs:265\n",
      "Scene:0044 ims:57 total valid pairs:808 selected pairs:114\n",
      "Scene:0046 ims:94 total valid pairs:786 selected pairs:500\n",
      "Scene:0047 ims:52 total valid pairs:261 selected pairs:236\n",
      "Scene:0048 ims:178 total valid pairs:3427 selected pairs:500\n",
      "Scene:0049 ims:71 total valid pairs:249 selected pairs:138\n",
      "Scene:0050 ims:267 total valid pairs:4599 selected pairs:500\n",
      "Scene:0056 ims:348 total valid pairs:2656 selected pairs:500\n",
      "Scene:0058 ims:56 total valid pairs:848 selected pairs:314\n",
      "Scene:0060 ims:16 total valid pairs:1778 selected pairs:16\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0061 ims:435 total valid pairs:12891 selected pairs:500\n",
      "Scene:0062 ims:123 total valid pairs:1562 selected pairs:500\n",
      "Skip scene 0063\n",
      "Scene:0064 ims:44 total valid pairs:538 selected pairs:93\n",
      "Scene:0065 ims:269 total valid pairs:5167 selected pairs:500\n",
      "Scene:0067 ims:108 total valid pairs:1291 selected pairs:500\n",
      "Scene:0070 ims:171 total valid pairs:4964 selected pairs:500\n",
      "Scene:0071 ims:172 total valid pairs:1290 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0076 ims:131 total valid pairs:2597 selected pairs:500\n",
      "Scene:0078 ims:91 total valid pairs:1182 selected pairs:444\n",
      "Scene:0083 ims:229 total valid pairs:2979 selected pairs:500\n",
      "Scene:0086 ims:220 total valid pairs:2029 selected pairs:500\n",
      "Scene:0087 ims:39 total valid pairs:382 selected pairs:121\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0090 ims:174 total valid pairs:1635 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0094 ims:105 total valid pairs:1949 selected pairs:500\n",
      "Scene:0095 ims:56 total valid pairs:954 selected pairs:86\n",
      "Scene:0098 ims:210 total valid pairs:5566 selected pairs:500\n",
      "Scene:0099 ims:102 total valid pairs:974 selected pairs:361\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0100 ims:324 total valid pairs:3032 selected pairs:500\n",
      "Scene:0101 ims:386 total valid pairs:3900 selected pairs:500\n",
      "Scene:0102 ims:75 total valid pairs:808 selected pairs:158\n",
      "Scene:0103 ims:268 total valid pairs:11089 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0104 ims:290 total valid pairs:8717 selected pairs:500\n",
      "Scene:0105 ims:418 total valid pairs:10257 selected pairs:500\n",
      "Scene:0107 ims:16 total valid pairs:2964 selected pairs:22\n",
      "Scene:0115 ims:354 total valid pairs:27077 selected pairs:500\n",
      "Scene:0117 ims:177 total valid pairs:2171 selected pairs:500\n",
      "Scene:0121 ims:2 total valid pairs:5 selected pairs:1\n",
      "Scene:0122 ims:496 total valid pairs:7101 selected pairs:500\n",
      "Scene:0129 ims:30 total valid pairs:262 selected pairs:78\n",
      "Scene:0130 ims:237 total valid pairs:10119 selected pairs:500\n",
      "Scene:0133 ims:0 total valid pairs:0 selected pairs:0\n",
      "Scene:0137 ims:113 total valid pairs:1616 selected pairs:219\n",
      "Scene:0141 ims:311 total valid pairs:2732 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0143 ims:373 total valid pairs:15534 selected pairs:500\n",
      "Scene:0147 ims:289 total valid pairs:4838 selected pairs:500\n",
      "Scene:0151 ims:106 total valid pairs:502 selected pairs:179\n",
      "Scene:0156 ims:72 total valid pairs:3636 selected pairs:500\n",
      "Scene:0160 ims:228 total valid pairs:3523 selected pairs:500\n",
      "Scene:0162 ims:83 total valid pairs:652 selected pairs:304\n",
      "Scene:0168 ims:11 total valid pairs:38 selected pairs:15\n",
      "Scene:0175 ims:14 total valid pairs:455 selected pairs:21\n",
      "Scene:0176 ims:324 total valid pairs:7372 selected pairs:500\n",
      "Scene:0177 ims:161 total valid pairs:1682 selected pairs:500\n",
      "Scene:0178 ims:40 total valid pairs:119 selected pairs:88\n",
      "Scene:0181 ims:93 total valid pairs:458 selected pairs:406\n",
      "Scene:0183 ims:385 total valid pairs:2885 selected pairs:500\n",
      "Scene:0185 ims:59 total valid pairs:354 selected pairs:219\n",
      "Scene:0186 ims:13 total valid pairs:298 selected pairs:19\n",
      "Scene:0189 ims:331 total valid pairs:5140 selected pairs:500\n",
      "Scene:0190 ims:152 total valid pairs:1916 selected pairs:500\n",
      "Scene:0197 ims:90 total valid pairs:1832 selected pairs:442\n",
      "Scene:0200 ims:278 total valid pairs:16403 selected pairs:500\n",
      "Scene:0204 ims:5 total valid pairs:183 selected pairs:3\n",
      "Scene:0205 ims:80 total valid pairs:638 selected pairs:335\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0212 ims:67 total valid pairs:631 selected pairs:313\n",
      "Scene:0214 ims:108 total valid pairs:2923 selected pairs:500\n",
      "Scene:0217 ims:24 total valid pairs:603 selected pairs:200\n",
      "Scene:0223 ims:57 total valid pairs:1361 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0224 ims:146 total valid pairs:2386 selected pairs:500\n",
      "Scene:0229 ims:8 total valid pairs:26 selected pairs:7\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0235 ims:394 total valid pairs:13660 selected pairs:500\n",
      "Scene:0238 ims:67 total valid pairs:685 selected pairs:230\n",
      "Scene:0240 ims:181 total valid pairs:2809 selected pairs:500\n",
      "Scene:0243 ims:219 total valid pairs:14494 selected pairs:500\n",
      "Scene:0252 ims:226 total valid pairs:2035 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0257 ims:88 total valid pairs:865 selected pairs:281\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0258 ims:332 total valid pairs:3783 selected pairs:500\n",
      "Scene:0265 ims:120 total valid pairs:4244 selected pairs:500\n",
      "Scene:0269 ims:61 total valid pairs:774 selected pairs:106\n",
      "Scene:0271 ims:52 total valid pairs:396 selected pairs:263\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0275 ims:174 total valid pairs:2617 selected pairs:500\n",
      "Scene:0277 ims:69 total valid pairs:936 selected pairs:160\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0281 ims:192 total valid pairs:1670 selected pairs:500\n",
      "Scene:0285 ims:48 total valid pairs:429 selected pairs:260\n",
      "Scene:0286 ims:63 total valid pairs:478 selected pairs:202\n",
      "Scene:0290 ims:61 total valid pairs:743 selected pairs:200\n",
      "Scene:0294 ims:26 total valid pairs:184 selected pairs:46\n",
      "Scene:0299 ims:270 total valid pairs:9945 selected pairs:500\n",
      "Scene:0303 ims:77 total valid pairs:380 selected pairs:285\n",
      "Scene:0306 ims:190 total valid pairs:1910 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0307 ims:155 total valid pairs:809 selected pairs:500\n",
      "Scene:0312 ims:156 total valid pairs:3647 selected pairs:500\n",
      "Scene:0323 ims:111 total valid pairs:2151 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0326 ims:389 total valid pairs:19098 selected pairs:500\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Scene:0327 ims:146 total valid pairs:7280 selected pairs:439\n",
      "Scene:0331 ims:420 total valid pairs:38561 selected pairs:500\n",
      "Scene:0335 ims:217 total valid pairs:2019 selected pairs:500\n",
      "Scene:0341 ims:189 total valid pairs:20061 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0348 ims:114 total valid pairs:1837 selected pairs:298\n",
      "Scene:0349 ims:8 total valid pairs:17 selected pairs:6\n",
      "Scene:0360 ims:182 total valid pairs:2740 selected pairs:500\n",
      "Scene:0366 ims:108 total valid pairs:5272 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0377 ims:382 total valid pairs:4253 selected pairs:500\n",
      "Scene:0380 ims:320 total valid pairs:7113 selected pairs:500\n",
      "Scene:0387 ims:74 total valid pairs:443 selected pairs:257\n",
      "Scene:0389 ims:174 total valid pairs:1900 selected pairs:500\n",
      "Scene:0394 ims:158 total valid pairs:4276 selected pairs:500\n",
      "Scene:0402 ims:97 total valid pairs:1018 selected pairs:292\n",
      "Scene:0406 ims:101 total valid pairs:478 selected pairs:282\n",
      "Scene:0407 ims:512 total valid pairs:17546 selected pairs:500\n",
      "Scene:0411 ims:291 total valid pairs:21699 selected pairs:500\n",
      "Scene:0412 ims:18 total valid pairs:158 selected pairs:130\n",
      "Scene:0430 ims:7 total valid pairs:35 selected pairs:29\n",
      "Scene:0443 ims:17 total valid pairs:66 selected pairs:45\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0446 ims:214 total valid pairs:3198 selected pairs:500\n",
      "Scene:0455 ims:242 total valid pairs:4370 selected pairs:500\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0472 ims:193 total valid pairs:1967 selected pairs:500\n",
      "Scene:0474 ims:51 total valid pairs:1716 selected pairs:323\n",
      "Scene:0476 ims:10 total valid pairs:1177 selected pairs:16\n",
      "Inaccurate matches or intrinsics\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:0478 ims:167 total valid pairs:4400 selected pairs:500\n",
      "Scene:0482 ims:89 total valid pairs:489 selected pairs:343\n",
      "Scene:0493 ims:329 total valid pairs:23795 selected pairs:500\n",
      "Scene:0496 ims:333 total valid pairs:16463 selected pairs:500\n",
      "Scene:0505 ims:181 total valid pairs:2864 selected pairs:500\n",
      "Scene:0559 ims:195 total valid pairs:2828 selected pairs:500\n",
      "Scene:0733 ims:65 total valid pairs:268 selected pairs:184\n",
      "Scene:0768 ims:2 total valid pairs:262 selected pairs:1\n",
      "Scene:0860 ims:174 total valid pairs:1809 selected pairs:500\n",
      "Scene:1001 ims:38 total valid pairs:75 selected pairs:62\n",
      "Scene:1017 ims:346 total valid pairs:1583 selected pairs:500\n",
      "Skip scene 1589\n",
      "Scene:3346 ims:69 total valid pairs:797 selected pairs:254\n",
      "Scene:4541 ims:337 total valid pairs:12628 selected pairs:500\n",
      "Scene:5000 ims:0 total valid pairs:1120 selected pairs:0\n",
      "Scene:5001 ims:0 total valid pairs:1166 selected pairs:0\n",
      "Scene:5002 ims:0 total valid pairs:1577 selected pairs:0\n",
      "Scene:5003 ims:0 total valid pairs:859 selected pairs:0\n",
      "Scene:5004 ims:0 total valid pairs:4405 selected pairs:0\n",
      "Scene:5005 ims:0 total valid pairs:3219 selected pairs:0\n",
      "Scene:5006 ims:0 total valid pairs:2277 selected pairs:0\n",
      "Scene:5007 ims:0 total valid pairs:3321 selected pairs:0\n",
      "Scene:5008 ims:0 total valid pairs:1752 selected pairs:0\n",
      "Scene:5009 ims:0 total valid pairs:3381 selected pairs:0\n",
      "Scene:5010 ims:0 total valid pairs:2274 selected pairs:0\n",
      "Scene:5011 ims:0 total valid pairs:1681 selected pairs:0\n",
      "Scene:5012 ims:0 total valid pairs:2221 selected pairs:0\n",
      "Scene:5013 ims:0 total valid pairs:4001 selected pairs:0\n",
      "Scene:5014 ims:25 total valid pairs:122 selected pairs:122\n",
      "Scene:5015 ims:28 total valid pairs:277 selected pairs:277\n",
      "Scene:5016 ims:26 total valid pairs:240 selected pairs:240\n",
      "Inaccurate matches or intrinsics\n",
      "Scene:5017 ims:385 total valid pairs:4820 selected pairs:500\n",
      "Scene:5018 ims:56 total valid pairs:304 selected pairs:304\n",
      "Can not open corrupted_scenes: (21, 'Is a directory')\n",
      "Save mathces to ../data_pairs/generated/megadepth_pairs.ov0.35_imrat1.5.pair500.excl_test.npy.\n",
      "Finished, total valid pairs:972369 used scenes:160 pairs:60661 \n",
      "Overlapping bins=[0.15 0.25 0.35 0.45 0.55 0.65 0.75 0.85 0.95] hist=[    0     0 36304 15067  5712  2247   895   326]\n"
     ]
    }
   ],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "%matplotlib inline\n",
    "import sys\n",
    "sys.path.append('..')\n",
    "\n",
    "import os\n",
    "import numpy as np\n",
    "from argparse import Namespace\n",
    "import cv2\n",
    "import torch\n",
    "from utils.common.setup_helper import lprint\n",
    "\n",
    "import glob\n",
    "from PIL import Image\n",
    "from utils.eval.geometry import abs2relapose, pose2fund\n",
    "from utils.eval.measure import sampson_distance\n",
    "from transforms3d.quaternions import mat2quat, quat2mat\n",
    "from utils.datasets.preprocess import crop_from_bottom_right\n",
    "\n",
    "args = Namespace(base_dir='../data/MegaDepth_undistort',\n",
    "                 save_dir='../data_pairs/generated',                \n",
    "                 min_overlap_ratio=0.35, im_target_ratio=1.5, \n",
    "                 max_scene_pairs=500, exclude_tag='excl_test')\n",
    "\n",
    "base_dir = args.base_dir\n",
    "scene_info_dir = os.path.join(base_dir, 'scene_info')\n",
    "\n",
    "# Output dir for log and match_pairs npy\n",
    "save_dir = args.save_dir\n",
    "if not os.path.exists(save_dir):\n",
    "    os.makedirs(save_dir)\n",
    "log_path = os.path.join(save_dir, 'megadepth_pair.log')\n",
    "log = open(log_path, 'a')\n",
    "lprint_ = lambda s: lprint(s, log)\n",
    "lprint_(str(args))\n",
    "    \n",
    "min_overlap_ratio = args.min_overlap_ratio\n",
    "im_target_ratio = args.im_target_ratio\n",
    "max_scene_pairs = args.max_scene_pairs  # At most take such amount of pairs per scene\n",
    "\n",
    "scene_overlappings = []\n",
    "match_dict = {}  # {'ims', 'pairs'}\n",
    "total_valid_pairs = 0\n",
    "selected_pairs = 0\n",
    "scene_files = sorted(os.listdir(scene_info_dir))\n",
    "\n",
    "# Exclude phototuorism scenes, incase one wants to evaluate on the image matching challenge\n",
    "exclude_tag = args.exclude_tag\n",
    "exclude_sce = []\n",
    "if exclude_tag == 'excl_test':\n",
    "    exclude_sce = ['0024', '0021', '0025', '1589',\n",
    "                  '0019', '0008', '0032', '0063']\n",
    "elif exclude_tag == 'excl_all': \n",
    "    exclude_sce = ['0024', '0021', '0025', '1589',\n",
    "                   '0019', '0008', '0032', '0063',\n",
    "                   '0015', '0022']\n",
    "\n",
    "\n",
    "lprint_('Start process {} scenes ......'.format(len(scene_files)))\n",
    "for scene_file in scene_files:\n",
    "    scene_name = scene_file.split('.')[0]\n",
    "    if scene_name in exclude_sce:\n",
    "        lprint_(f'Skip scene {scene_name}')\n",
    "        continue\n",
    "    \n",
    "    # Load scene information\n",
    "    scene_info_path = os.path.join(scene_info_dir, scene_file)\n",
    "    try:        \n",
    "        scene_info = dict(np.load(scene_info_path, allow_pickle=True))        \n",
    "    except Exception as err:\n",
    "        lprint_('Can not open {}: {}'.format(scene_file, err.args))\n",
    "        continue\n",
    "\n",
    "    # Select valid pairs\n",
    "    overlap_matrix = scene_info['overlap_matrix']\n",
    "    scale_ratio_matrix = scene_info['scale_ratio_matrix']\n",
    "    valid =  np.logical_and(\n",
    "        np.logical_and(\n",
    "            overlap_matrix >= min_overlap_ratio,\n",
    "            overlap_matrix < 1\n",
    "        ),\n",
    "        scale_ratio_matrix <= np.inf\n",
    "    )\n",
    "    valid_pair_ids = np.vstack(np.where(valid))   # 2,N\n",
    "    valid_num = valid_pair_ids.shape[1]\n",
    "    total_valid_pairs += valid_num\n",
    "    \n",
    "    # Load scene information    \n",
    "    image_paths = scene_info['image_paths']\n",
    "    depth_paths = scene_info['depth_paths']\n",
    "    points3D_id_to_2D = scene_info['points3D_id_to_2D']\n",
    "    points3D_id_to_ndepth = scene_info['points3D_id_to_ndepth']\n",
    "    intrinsics = scene_info['intrinsics']\n",
    "    poses = scene_info['poses']   \n",
    "\n",
    "    # Iterate over pairs\n",
    "    imlist = {}\n",
    "    pairs = []\n",
    "    selected_ids = np.arange(valid_num)\n",
    "    np.random.shuffle(selected_ids)\n",
    "    for pair_idx in selected_ids:\n",
    "        idx1 = valid_pair_ids[0, pair_idx]\n",
    "        idx2 = valid_pair_ids[1, pair_idx]\n",
    "        overlap = overlap_matrix[idx1, idx2]\n",
    "\n",
    "        # Check image ratios\n",
    "        K1 = intrinsics[idx1]\n",
    "        K2 = intrinsics[idx2]  \n",
    "        w1, h1 = 2 * K1[:2, 2]\n",
    "        w2, h2 = 2 * K2[:2, 2]                    \n",
    "        if w1 >= h1 and w2 >= h2:\n",
    "            # Landscape pairs            \n",
    "            crop1 = crop_from_bottom_right(w1, h1, target_ratio=im_target_ratio)\n",
    "            crop2 = crop_from_bottom_right(w2, h2, target_ratio=im_target_ratio)\n",
    "            if not crop1 or not crop2:\n",
    "                continue\n",
    "        else:\n",
    "            # Ignore portrait and mixed pairs \n",
    "            continue            \n",
    "\n",
    "        # Find common 3D points of the curremt image pair\n",
    "        common_pts3D = np.array(list(\n",
    "            points3D_id_to_2D[idx1].keys() &\n",
    "            points3D_id_to_2D[idx2].keys()\n",
    "        ))\n",
    "\n",
    "        # Remove matches with bad depth scale??\n",
    "        pt_nd1 = np.array([points3D_id_to_ndepth[idx1][pid] for pid in common_pts3D])\n",
    "        pt_nd2 = np.array([points3D_id_to_ndepth[idx2][pid] for pid in common_pts3D])\n",
    "        scale_ratio = np.maximum(pt_nd1 / pt_nd2, pt_nd2 / pt_nd1)\n",
    "        common_pts3D = common_pts3D[np.where(scale_ratio <= np.inf)[0]]\n",
    "\n",
    "        # Obtain 2D correspondences\n",
    "        matches = []\n",
    "        for pid in common_pts3D:\n",
    "            p1 = points3D_id_to_2D[idx1][pid]\n",
    "            p2 = points3D_id_to_2D[idx2][pid]\n",
    "            matches.append((p1[0], p1[1], p2[0], p2[1]))\n",
    "        matches = np.array(matches)\n",
    "        \n",
    "       # Calculate relative poses    \n",
    "        pose1 = poses[idx1]\n",
    "        r1 = pose1[:3, :3]\n",
    "        t1 = pose1[:3, 3]\n",
    "        c1 = - r1.T.dot(t1)\n",
    "        q1 = mat2quat(r1)\n",
    "\n",
    "        pose2 = poses[idx2]\n",
    "        r2 = pose2[:3, :3]\n",
    "        t2 = pose2[:3, 3]\n",
    "        c2 = - r2.T.dot(t2)\n",
    "        q2 = mat2quat(r2)\n",
    "\n",
    "        t, q = abs2relapose(c1, c2, q1, q2)\n",
    "        R = quat2mat(q)\n",
    "\n",
    "        # Check epipolar errors\n",
    "        K1 = intrinsics[idx1]\n",
    "        K2 = intrinsics[idx2]  \n",
    "        F = pose2fund(K1, K2, R, t)\n",
    "\n",
    "        pts1 = matches[:, :2]\n",
    "        pts2 = matches[:, 2:]\n",
    "        dist  = sampson_distance(pts1, pts2, F)\n",
    "        if np.mean(dist) > 1:\n",
    "            print('Inaccurate matches or intrinsics')\n",
    "            continue        \n",
    "            \n",
    "        # Wrap up pair data\n",
    "        im1_name = image_paths[idx1].replace('Undistorted_SfM/', '')\n",
    "        im2_name = image_paths[idx2].replace('Undistorted_SfM/', '')\n",
    "        \n",
    "        if im1_name not in imlist:\n",
    "            imlist[im1_name] = Namespace(name=im1_name, crop=crop1)      \n",
    "        if im2_name not in imlist:\n",
    "            imlist[im2_name] = Namespace(name=im2_name, crop=crop2)         \n",
    "\n",
    "        pairs.append(Namespace(im1=im1_name, im2=im2_name, overlap=overlap, \n",
    "                               K1=K1, K2=K2, t=t, q=q, R=R, crop1=crop1, crop2=crop2))\n",
    "        scene_overlappings.append(overlap)\n",
    "        if len(pairs) >= max_scene_pairs:\n",
    "            break    \n",
    "    if len(pairs) > 0:\n",
    "        selected_pairs += len(pairs)\n",
    "        scene_dict = dict(ims=list(imlist.values()), pairs=pairs)\n",
    "        match_dict[scene_name] = scene_dict\n",
    "    lprint_('Scene:{} ims:{} total valid pairs:{} selected pairs:{}'.format(scene_name, len(imlist), valid_num, len(pairs)))    \n",
    "    \n",
    "# Save results    \n",
    "if exclude_tag:\n",
    "    exclude_tag = '.' + exclude_tag\n",
    "match_npy_name = 'megadepth_pairs.ov{}_imrat{}.pair{}{}.npy'.format(min_overlap_ratio, im_target_ratio, max_scene_pairs, exclude_tag)\n",
    "match_npy_path = os.path.join(save_dir, match_npy_name)\n",
    "np.save(match_npy_path, match_dict)\n",
    "lprint_('Save mathces to {}.'.format(match_npy_path))    \n",
    "lprint_('Finished, total valid pairs:{} used scenes:{} pairs:{} '.format(total_valid_pairs, len(match_dict), selected_pairs))\n",
    "bins = np.arange(0.15, 1.01, 0.1)\n",
    "hist = np.histogram(scene_overlappings, bins=bins)[0]\n",
    "lprint_('Overlapping bins={} hist={}'.format(bins, hist))\n",
    "log.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:patch2pix]",
   "language": "python",
   "name": "conda-env-patch2pix-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
